package com.example.springbootredis.controller;

import cn.hutool.core.util.ObjectUtil;
import com.example.springbootredis.entity.User;
import com.example.springbootredis.util.BaseResp;
import com.example.springbootredis.util.TestDataUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisZSetCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashSet;
import java.util.List;
import java.util.Set;


@Slf4j
@Api("redis【zSet】")
@RestController
@RequestMapping("/redis/zSet")
public class RedisZSetController {

    @Autowired
    RedisTemplate redisTemplate;

    //-----------------redis zset start-------------
    String zSet_test_key = "zSet_test";

    String zSet_test_key_1 = "zSet_test_1";


    @ApiOperation("初始化数据")
    @RequestMapping(value = "/initData",method = RequestMethod.GET)
    public BaseResp zSet_initData(){
        log.info("zSet_initData start");
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        List<User> users = TestDataUtil.getUsers();
        for (User user : users) {
            setOperations.add(zSet_test_key,user,user.getAge());
        }
        log.info("zSet_initData end");
        return BaseResp.buildSuccess();
    }

    @ApiOperation("【zSet】初始化数据(添加 类型是TypedTuple的set集合)")
    @RequestMapping(value = "/initData_tuples",method = RequestMethod.GET)
    public BaseResp zSet_initData1(){
        log.info("zSet_initData1 start");
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        List<User> users = TestDataUtil.getUsers();

        Set<ZSetOperations.TypedTuple<User>> tuples = new HashSet<>();
        for (User user : users) {
            tuples.add(ZSetOperations.TypedTuple.of(user,user.getAge().doubleValue()));
        }
        Long resp = setOperations.add(zSet_test_key, tuples);
        log.info("zSet_initData1 end resp:{}",resp);
        return BaseResp.buildSuccess();
    }

    @ApiOperation("【zSet】初始化数据 (value值只存id)")
    @RequestMapping(value = "/initData_value",method = RequestMethod.GET)
    public BaseResp initData_value(){
        log.info("initData_value start");
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        List<User> users = TestDataUtil.getUsers();
        for (User user : users) {
            setOperations.add(zSet_test_key_1,user.getId(),user.getAge());
        }
        log.info("initData_value end");
        return BaseResp.buildSuccess();
    }

    @ApiOperation("计算有序集合中指定字典区间(minScore -> maxScore)内成员数量。")
    @RequestMapping(value = "/count",method = RequestMethod.GET)
    public BaseResp zSet_count(@RequestParam("minScore")Double minScore,@RequestParam("maxScore")Double maxScore){
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        Long count =setOperations.count(zSet_test_key_1,minScore,maxScore);
        return BaseResp.buildDataSuccess(count);
    }

    @ApiOperation("有序集合中，元素score原子自增")
    @RequestMapping(value = "/incrementScore",method = RequestMethod.GET)
    public BaseResp incrementScore(@RequestParam("uid")Integer uid,@RequestParam(value = "score",defaultValue = "1")Integer score){
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        Double count = setOperations.incrementScore(zSet_test_key_1,uid,score);
        return BaseResp.buildDataSuccess(count);
    }
    @ApiOperation("取有序集合中 成员数量")
    @RequestMapping(value = "/count/zCard",method = RequestMethod.GET)
    public BaseResp zCard(){
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        Long count = setOperations.zCard(zSet_test_key_1);
        return BaseResp.buildDataSuccess(count);
    }

    @ApiOperation("取当前成员所在 集合的排名【升序的排名（按照score从低到高的 排名）】【排名是所在下标 从0开始】")
    @RequestMapping(value = "/get/rank",method = RequestMethod.GET)
    public BaseResp rank(@RequestParam("uid")Integer uid){
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        Long rank = setOperations.rank(zSet_test_key_1,uid);
        log.info("rank uid:{} rank:{}",uid,rank);
        return BaseResp.buildDataSuccess("所在排名"+(rank+1));
    }


    @ApiOperation("取当前成员所在 集合的排名【降序的排名（按照score从高到低的 排名）】【排名是所在下标 从0开始】")
    @RequestMapping(value = "/get/rank/reverse",method = RequestMethod.GET)
    public BaseResp reverseRank(@RequestParam("uid")Integer uid){
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        Long reverseRank = setOperations.reverseRank(zSet_test_key_1,uid);
        log.info("rank uid:{} reverseRank:{}",uid,reverseRank);
        return BaseResp.buildDataSuccess("所在排名"+(reverseRank+1));
    }



    @ApiOperation("根据设置的最大和最小的范围，返回字典排序集合中的元素")
    @RequestMapping(value = "/get/rangeByLex",method = RequestMethod.GET)
    public BaseResp rangeByLex(@RequestParam(value = "minScore",required = true,defaultValue = "0")Double minScore,
                               @RequestParam(value = "maxScore",required = true,defaultValue = "999")Double maxScore){
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        RedisZSetCommands.Range range = new RedisZSetCommands.Range().gte(minScore).lte(maxScore);
        Set resp = setOperations.rangeByLex(zSet_test_key_1, range);
        log.info("rangeByLex resp:{}",resp);
        return BaseResp.buildDataSuccess(resp);
    }


    @ApiOperation("列表查询【根据（score）排序，正序返回「value」】- 查询条件【起始位置 start - 结束位置 end】")
    @RequestMapping(value = "/query/range",method = RequestMethod.GET)
    public BaseResp range(@RequestParam(value = "start",required = false,defaultValue = "0")Long start,@RequestParam(value = "end",required = false,defaultValue = "-1")Long end){
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        Set resp = setOperations.range(zSet_test_key_1,start,end);
        log.info("reverseRange resp:{}",resp);
        return BaseResp.buildDataSuccess(resp);
    }

    @ApiOperation("列表查询（根据（score）排序，倒序返回「value」）- 查询条件【起始位置 start - 结束位置 end】")
    @RequestMapping(value = "/query/range/reverse",method = RequestMethod.GET)
    public BaseResp reverseRange(@RequestParam(value = "start",required = false,defaultValue = "0")Long start,@RequestParam(value = "end",required = false,defaultValue = "-1")Long end){
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        Set resp = setOperations.reverseRange(zSet_test_key_1,start,end);
        log.info("reverseRange resp:{}",resp);
        return BaseResp.buildDataSuccess(resp);
    }


    @ApiOperation(value = "列表查询【根据（score）排序，正序返回「value」】- 查询条件【最小&最高】score")
    @RequestMapping(value = "/query/rangeByScore",method = RequestMethod.GET)
    public BaseResp rangeByScore(@RequestParam(value = "minScore",required = false)Double minScore,@RequestParam(value = "maxScore",required = false)Double maxScore){
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        minScore = ObjectUtil.defaultIfNull(minScore,Double.MIN_VALUE);
        maxScore = ObjectUtil.defaultIfNull(maxScore,Double.MAX_VALUE);
        Set resp = setOperations.rangeByScore(zSet_test_key_1, minScore,maxScore);
        log.info("rangeByScore resp:{}",resp);
        return BaseResp.buildDataSuccess(resp);
    }

    @ApiOperation(value = "列表查询（根据（score）排序，倒序返回「value」）-查询条件【最小&最高】score")
    @RequestMapping(value = "/query/rangeByScore/reverse",method = RequestMethod.GET)
    public BaseResp reverseRangeByScore(@RequestParam(value = "minScore",required = false)Double minScore,@RequestParam(value = "maxScore",required = false)Double maxScore){
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        minScore = ObjectUtil.defaultIfNull(minScore,Double.MIN_VALUE);
        maxScore = ObjectUtil.defaultIfNull(maxScore,Double.MAX_VALUE);
        Set resp = setOperations.reverseRangeByScore(zSet_test_key_1, minScore,maxScore);
        log.info("reverseRangeByScore resp:{}",resp);
        return BaseResp.buildDataSuccess(resp);
    }


    @ApiOperation("列表查询（根据（score）排序，正序返回「score & value」 ）- 查询条件【最小&最高】score")
    @RequestMapping(value = "/query/rangeByScoreWithScores",method = RequestMethod.GET)
    public BaseResp rangeByScoreWithScores(@RequestParam(value = "minScore",required = false)Double minScore,@RequestParam(value = "maxScore",required = false)Double maxScore){
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        minScore = ObjectUtil.defaultIfNull(minScore,Double.MIN_VALUE);
        maxScore = ObjectUtil.defaultIfNull(maxScore,Double.MAX_VALUE);

        Set resp = setOperations.rangeByScoreWithScores(zSet_test_key_1, minScore,maxScore);
        log.info("rangeByScore resp:{}",resp);
        return BaseResp.buildDataSuccess(resp);
    }

    @ApiOperation("列表查询（根据（score）排序 倒序返回「score & value」）- 查询条件【最小&最高】score")
    @RequestMapping(value = "/query/rangeByScoreWithScores/reverse",method = RequestMethod.GET)
    public BaseResp reverseRangeByScoreWithScores(@RequestParam(value = "minScore",required = false)Double minScore,@RequestParam(value = "maxScore",required = false)Double maxScore){
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        minScore = ObjectUtil.defaultIfNull(minScore,Double.MIN_VALUE);
        maxScore = ObjectUtil.defaultIfNull(maxScore,Double.MAX_VALUE);

        Set resp = setOperations.reverseRangeByScoreWithScores(zSet_test_key_1, minScore,maxScore);
        log.info("reverseRangeByScoreWithScores resp:{}",resp);
        return BaseResp.buildDataSuccess(resp);
    }


    String zSet_test_key_union_1 = "zSet_test_key_union_1";
    String zSet_test_key_union_2 = "zSet_test_key_union_2";
    String zSet_test_key_union_desc = "zSet_test_key_union_desc";

    @ApiOperation("多个有序集合，合并成一个新的有序集合（并集） 元素相同的score想加")
    @RequestMapping(value = "/store/unionAndStore",method = RequestMethod.GET)
    public BaseResp unionAndStore(){
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        List<User> users = TestDataUtil.getUsers();
        for (User user : users) {
            setOperations.add(zSet_test_key_union_1,user.getId(),user.getAge());
        }

        setOperations.add(zSet_test_key_union_2,1,10000);

        setOperations.add(zSet_test_key_union_2,-1,-1);

        Long resp = setOperations.unionAndStore(zSet_test_key_union_1,zSet_test_key_union_2,zSet_test_key_union_desc);
        log.info("unionAndStore resp:{}",resp);
        return BaseResp.buildDataSuccess(resp);
    }


    String zSet_test_key_intersect_1 = "zSet_test_intersect_1";
    String zSet_test_key_intersect_2 = "zSet_test_intersect_2";
    String zSet_test_key_intersect_desc = "zSet_test_intersect_dest";

    @ApiOperation("两个有序集合-交集， 两个有序集合 都有相同的元素，并且score相加")
    @RequestMapping(value = "/store/intersectAndStore",method = RequestMethod.GET)
    public BaseResp intersectAndStore(){
        ZSetOperations setOperations  = redisTemplate.opsForZSet();
        List<User> users = TestDataUtil.getUsers();
        for (User user : users) {
            setOperations.add(zSet_test_key_intersect_1,user.getId(),user.getAge());
        }

        setOperations.add(zSet_test_key_intersect_2,1,100);
        setOperations.add(zSet_test_key_intersect_2,10003,100);

        Long resp = setOperations.intersectAndStore(zSet_test_key_intersect_1,zSet_test_key_intersect_2,zSet_test_key_intersect_desc);
        log.info("intersectAndStore resp:{}",resp);
        return BaseResp.buildDataSuccess(resp);
    }


    //-----------------redis zset end-------------
}
